package gamelogic

import (
	"math"
	"server_cluster/common/config"
	"server_cluster/common/gdconf"
	"server_cluster/common/logger"
	"server_cluster/common/mysock"
	"server_cluster/common/protoc/pb"
	"server_cluster/logic/sharemem"
	"slices"
)

func AddUserRole(roleId int32, user *sharemem.User) {
	ok := AddRole(roleId, user)
	if !ok {
		logger.Error("add u role fail, uid: %v", user.GetUid())
		return
	}
	role := user.GetRoleById(roleId)
	SendMsg(config.SC_RoleUpdateNtf, &pb.SC_RoleUpdateNtf{Role: user.PacketUserRole(role)}, nil, user)
	UnlockCodex(pb.CodexType_CODEX_ROLE, roleId, user)
}

func AddRole(roleId int32, user *sharemem.User) bool {
	roleConfig := gdconf.GetRoleConfig(roleId)
	if roleConfig == nil {
		return false
	}
	role := user.GetRoleById(roleId)
	if role == nil {
		// 添加新角色
		for i := 0; i < len(user.Role); i++ {
			role = &(user.Role[i])
			if role.IsUse() {
				continue
			}
			role.CreateRole(roleConfig)
			// 添加索引
			user.Add2RoleMap(roleId, role)
			// 默认解锁天赋
			for _, roleTalentConfig := range gdconf.GetRoleTalentConfigMap() {
				if roleTalentConfig.TalentGroup != roleConfig.TalentGroup {
					continue
				}
				if roleTalentConfig.DefaultUnlock {
					RoleUnlockTalent(roleId, roleTalentConfig.TalentId, true, user)
				}
			}
			role.CurrEnergy = 0
			role.CurrHp = user.GetUserRoleFightProp(role.GetId())[config.FIGHT_PROP_HP]
			// 默认解锁队长技能
			captainSkillConfig := gdconf.GetCaptainSkillConfig(roleId)
			if captainSkillConfig != nil {
				for _, captainSkill := range captainSkillConfig.CaptainSkillList {
					if captainSkill.UnlockCond != nil {
						continue
					}
					role.AddCaptainSkill(captainSkill.CaptainSkillGroup)
				}
			}
			//role.SetSync()
			TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ROLE_COUNT, true)
			TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ROLE_LEVEL, true)
			return true
		}
		logger.Error("no empty role found, uid: %v", user.GetUid())
		return false
	} else {
		// 转化角色碎片道具
		if roleConfig.ConvItem != nil {
			AddItems(map[int32]int32{roleConfig.ConvItem.ItemId: roleConfig.ConvItem.ItemCount}, user)
		}
		return true
	}
}

// RoleUpgrade 角色升级
func RoleUpgrade(role *sharemem.Role, req *pb.CS_Role_Action, rsp *pb.SC_Role_Action, user *sharemem.User) int16 {
	// 检查配置
	roleConfig := gdconf.GetRoleConfig(req.RoleId)
	if roleConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	rolePromoteConfig := gdconf.GetRolePromoteConfigByGroupAndPromote(roleConfig.PromoteGroup, int32(role.Promote))
	if rolePromoteConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	// 角色等级是否达到限制
	if role.Level >= int16(rolePromoteConfig.LevelLimit) {
		logger.Error("role level < level limit, level: %v, uid: %v", role.Level, user.GetUid())
		return config.SERVER_ERROR
	}
	// 是否达到最大等级
	roleLevelConfig := gdconf.GetRoleLevelConfigByGroupAndLevel(roleConfig.LevelGroup, int32(role.Level))
	if roleLevelConfig == nil || roleLevelConfig.Exp == 0 {
		logger.Error("role max level limit, level: %v, uid: %v", role.Level, user.GetUid())
		return config.SERVER_ERROR
	}
	// 计算道具的总经验
	totalAddExp := int32(0)
	for _, item := range req.ItemList {
		itemActiveConfig := gdconf.GetItemUseConfig(item.Id)
		if itemActiveConfig == nil {
			return config.CONFIG_NOT_FOUND
		}
		if itemActiveConfig.Param[0] != gdconf.ItemUseTypeAddGlobalExp {
			logger.Error("item type is not exp, type: %v, uid: %v", itemActiveConfig.Param[0], user.GetUid())
			return config.SERVER_ERROR
		}
		totalAddExp += itemActiveConfig.Param[1] * item.Num
	}
	// 扣除道具
	SubItems(req.ItemList, user)
	var remainExp = role.PreAddExp(totalAddExp)
	goldExpRatio := gdconf.GetConstFloat("UPGRADECOST")
	ok := CostItems(map[int32]int32{gdconf.ITEM_GOLD: int32(float32(goldExpRatio) * float32(math.Max(float64(totalAddExp-remainExp), 0)))}, user)
	if !ok {
		return config.ITEM_NOT_ENOUGH
	}
	// 增加经验修改数据
	role.AddExp(totalAddExp)
	// 返回数据
	rsp.Role = user.PacketUserRole(role)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ROLE_UPGRADE, true)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ROLE_LEVEL, true)
	return config.OK
}

// RolePromote 角色升阶
func RolePromote(role *sharemem.Role, req *pb.CS_Role_Action, rsp *pb.SC_Role_Action, user *sharemem.User) int16 {
	// 检查配置
	roleConfig := gdconf.GetRoleConfig(req.RoleId)
	if roleConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	rolePromoteConfig := gdconf.GetRolePromoteConfigByGroupAndPromote(roleConfig.PromoteGroup, int32(role.Promote))
	if rolePromoteConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	// 声望等级是否满足
	if user.Level < int16(rolePromoteConfig.NeedPlayerLevel) {
		logger.Error("player level < need player level, level: %v, uid: %v", user.Level, user.GetUid())
		return config.SERVER_ERROR
	}
	// 角色等级是否满足
	if role.Level != int16(rolePromoteConfig.LevelLimit) {
		logger.Error("role level != level limit, level: %v, uid: %v", role.Level, user.GetUid())
		return config.SERVER_ERROR
	}
	// 是否达到最大等阶
	if gdconf.GetRolePromoteConfigByGroupAndPromote(roleConfig.PromoteGroup, int32(role.Promote+1)) == nil {
		logger.Error("role max promote limit, promote: %v, uid: %v", role.Promote, user.GetUid())
		return config.SERVER_ERROR
	}
	// 校验并扣除道具
	for _, material := range rolePromoteConfig.CostItemList {
		if !slices.ContainsFunc[[]*pb.Item_Req, *pb.Item_Req](req.ItemList, func(item *pb.Item_Req) bool {
			return item.Id == material.ItemId && item.Num == material.ItemCount
		}) {
			logger.Error("client req item not match with config, uid: %v", user.GetUid())
			return config.SERVER_ERROR
		}
	}
	SubItems(req.ItemList, user)
	ok := CostItems(map[int32]int32{gdconf.ITEM_GOLD: rolePromoteConfig.Gold}, user)
	if !ok {
		return config.ITEM_NOT_ENOUGH
	}
	// 角色升阶
	role.Promote++
	role.SetSync()
	// 返回数据
	rsp.Role = user.PacketUserRole(role)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ROLE_PROMOTE, true)
	return config.OK
}

// RoleRiseStar 角色升星
func RoleRiseStar(role *sharemem.Role, req *pb.CS_Role_Action, rsp *pb.SC_Role_Action, user *sharemem.User) int16 {
	// 检查配置
	roleConfig := gdconf.GetRoleConfig(req.RoleId)
	if roleConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	roleStarConfig := gdconf.GetRoleStarConfigByGroupAndStar(roleConfig.StarGroup, int32(role.Star+1))
	if roleStarConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	// 校验并扣除道具
	if roleStarConfig.CostItem != nil {
		if len(req.ItemList) != 1 || req.ItemList[0].Id != roleStarConfig.CostItem.ItemId || req.ItemList[0].Num != roleStarConfig.CostItem.ItemCount {
			logger.Error("client req item not match with config, uid: %v", user.GetUid())
			return config.SERVER_ERROR
		}
		SubItems(req.ItemList, user)
	}
	// 角色升星
	role.Star++
	role.SetSync()
	// 返回数据
	rsp.Role = user.PacketUserRole(role)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ROLE_STAR, true)
	return config.OK
}

func RoleUnlockTalent(roleId int32, talentId int32, forceUnlock bool, user *sharemem.User) bool {
	role := user.GetRoleById(roleId)
	if role == nil {
		logger.Error("role not exist, roleId: %v", roleId)
		return false
	}
	if role.GetTalent(talentId) != nil {
		logger.Error("role talent already unlock, talentId: %v", talentId)
		return false
	}
	roleTalentConfig := gdconf.GetRoleTalentConfig(talentId)
	if roleTalentConfig == nil {
		return false
	}
	if !forceUnlock {
		roleTalentEffectGroupConfig := gdconf.GetRoleTalentEffectGroupConfigByGroupAndLevel(roleTalentConfig.EffectGroup, 1)
		if roleTalentEffectGroupConfig == nil {
			return false
		}
		if int32(role.Promote) < roleTalentEffectGroupConfig.NeedPromote {
			logger.Error("role promote limit, curr: %v, need: %v", role.Promote, roleTalentEffectGroupConfig.NeedPromote)
			return false
		}
		ok := CostItems(map[int32]int32{roleTalentEffectGroupConfig.CostItem.ItemId: roleTalentEffectGroupConfig.CostItem.ItemCount}, user)
		if !ok {
			logger.Error("item not enough, cost: %v", roleTalentEffectGroupConfig.CostItem)
			return false
		}
	}
	ok := role.AddTalent(talentId)
	if !ok {
		return false
	}
	role.SetSync()
	return true
}

func RoleUpgradeTalent(roleId int32, talentId int32, user *sharemem.User) bool {
	role := user.GetRoleById(roleId)
	if role == nil {
		logger.Error("role not exist, roleId: %v", roleId)
		return false
	}
	talent := role.GetTalent(talentId)
	if talent == nil {
		logger.Error("role talent not found, roleId: %v, talentId: %v", roleId, talentId)
		return false
	}
	roleTalentConfig := gdconf.GetRoleTalentConfig(talentId)
	if roleTalentConfig == nil {
		return false
	}
	roleTalentEffectGroupConfig := gdconf.GetRoleTalentEffectGroupConfigByGroupAndLevel(roleTalentConfig.EffectGroup, int32(talent.Level)+1)
	if roleTalentEffectGroupConfig == nil {
		logger.Error("role talent is max level, roleId: %v, talentId: %v, talentLevel: %v", roleId, talent.TalentId, talent.Level)
		return false
	}
	if int32(role.Promote) < roleTalentEffectGroupConfig.NeedPromote {
		logger.Error("role promote limit, curr: %v, need: %v", role.Promote, roleTalentEffectGroupConfig.NeedPromote)
		return false
	}
	if roleTalentEffectGroupConfig.CostItem != nil {
		ok := CostItems(map[int32]int32{roleTalentEffectGroupConfig.CostItem.ItemId: roleTalentEffectGroupConfig.CostItem.ItemCount}, user)
		if !ok {
			logger.Error("item not enough, cost: %v", roleTalentEffectGroupConfig.CostItem)
			return false
		}
	}
	talent.Level++
	role.SetSync()
	return true
}

func TriggerUnlockCaptainSkill(questId int32, user *sharemem.User) {
	for _, captainSkillConfig := range gdconf.GetCaptainSkillConfigMap() {
		for _, captainSkill := range captainSkillConfig.CaptainSkillList {
			if captainSkill.UnlockCond == nil {
				continue
			}
			if captainSkill.UnlockCond.Cond != gdconf.CaptainSkillUnlockCondFinishQuest {
				continue
			}
			if captainSkill.UnlockCond.QuestId != questId {
				continue
			}
			role := user.GetRoleById(captainSkillConfig.RoleId)
			if role == nil {
				continue
			}
			role.AddCaptainSkill(captainSkill.CaptainSkillGroup)
		}
	}
}

//==========消息协议处理===============

// UserRoleAction 角色操作请求
func UserRoleAction(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_ROLE_ACTION, new(pb.CS_Role_Action), buf, user).(*pb.CS_Role_Action)
	if !ok {
		return config.PROTO_ERROR
	}

	rsp := &pb.SC_Role_Action{
		OpType: req.OpType,
		Status: config.OK,
		Role:   new(pb.User_Role),
	}

	// 检查角色
	role := user.GetRoleById(req.RoleId)
	if role == nil {
		return SendMsg(config.SC_ROLE_ACTION, &pb.SC_Role_Action{Status: config.OBJECT_NOT_FOUND}, buf, user)
	}
	// 检查道具
	ret := CheckSubItems(req.ItemList, user)
	if ret != config.OK {
		logger.Error("use item error code: %v, uid: %v", ret, user.GetUid())
		return SendMsg(config.SC_ROLE_ACTION, &pb.SC_Role_Action{Status: ret}, buf, user)
	}

	switch req.OpType {
	case config.ROLE_ACTION_OP_TYPE_UPGRADE:
		// 升级
		code := RoleUpgrade(role, req, rsp, user)
		if code != config.OK {
			return SendMsg(config.SC_ROLE_ACTION, &pb.SC_Role_Action{Status: int32(code)}, buf, user)
		}
	case config.ROLE_ACTION_OP_TYPE_PROMOTE:
		// 升阶
		code := RolePromote(role, req, rsp, user)
		if code != config.OK {
			return SendMsg(config.SC_ROLE_ACTION, &pb.SC_Role_Action{Status: int32(code)}, buf, user)
		}
	case config.ROLE_ACTION_OP_TYPE_RISESTAR:
		// 升星
		code := RoleRiseStar(role, req, rsp, user)
		if code != config.OK {
			return SendMsg(config.SC_ROLE_ACTION, &pb.SC_Role_Action{Status: int32(code)}, buf, user)
		}
	}

	// 返回响应
	return SendMsg(config.SC_ROLE_ACTION, rsp, buf, user)
}

func RoleTalentUnlockReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_RoleTalentUnlockReq, new(pb.CS_RoleTalentUnlockReq), buf, user).(*pb.CS_RoleTalentUnlockReq)
	if !ok {
		return config.PROTO_ERROR
	}

	ok = RoleUnlockTalent(req.RoleId, req.TalentId, false, user)
	if !ok {
		SendMsg(config.SC_RoleTalentUnlockRsp, &pb.SC_RoleTalentUnlockRsp{RetCode: config.SERVER_ERROR}, buf, user)
		return config.OK
	}

	role := user.GetRoleById(req.RoleId)
	if role != nil {
		SendMsg(config.SC_RoleUpdateNtf, &pb.SC_RoleUpdateNtf{Role: user.PacketUserRole(role)}, buf, user)
	}

	SendMsg(config.SC_RoleTalentUnlockRsp, &pb.SC_RoleTalentUnlockRsp{RetCode: config.OK, RoleId: req.RoleId, TalentId: req.TalentId}, buf, user)
	return config.OK
}

func RoleTalentUpgradeReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_RoleTalentUpgradeReq, new(pb.CS_RoleTalentUpgradeReq), buf, user).(*pb.CS_RoleTalentUpgradeReq)
	if !ok {
		return config.PROTO_ERROR
	}

	ok = RoleUpgradeTalent(req.RoleId, req.TalentId, user)
	if !ok {
		SendMsg(config.SC_RoleTalentUpgradeRsp, &pb.SC_RoleTalentUpgradeRsp{RetCode: config.SERVER_ERROR}, buf, user)
		return config.OK
	}

	role := user.GetRoleById(req.RoleId)
	if role == nil {
		logger.Error("role not exist, roleId: %v", req.RoleId)
		SendMsg(config.SC_RoleTalentUpgradeRsp, &pb.SC_RoleTalentUpgradeRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
	}
	SendMsg(config.SC_RoleUpdateNtf, &pb.SC_RoleUpdateNtf{Role: user.PacketUserRole(role)}, buf, user)

	SendMsg(config.SC_RoleTalentUpgradeRsp, &pb.SC_RoleTalentUpgradeRsp{RetCode: config.OK, RoleId: req.RoleId, TalentId: req.TalentId}, buf, user)
	return config.OK
}

func CaptainSkillUnlockReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_CaptainSkillUnlockReq, new(pb.CS_CaptainSkillUnlockReq), buf, user).(*pb.CS_CaptainSkillUnlockReq)
	if !ok {
		return config.PROTO_ERROR
	}

	captainSkillConfig := gdconf.GetCaptainSkillConfig(req.RoleId)
	if captainSkillConfig == nil {
		SendMsg(config.SC_CaptainSkillUnlockRsp, &pb.SC_CaptainSkillUnlockRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	var unlockCond *gdconf.CaptainSkillUnlockCond = nil
	for _, captainSkill := range captainSkillConfig.CaptainSkillList {
		if captainSkill.CaptainSkillGroup == req.CaptainSkillGroup {
			unlockCond = captainSkill.UnlockCond
			break
		}
	}
	if unlockCond == nil {
		SendMsg(config.SC_CaptainSkillUnlockRsp, &pb.SC_CaptainSkillUnlockRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	if unlockCond.Cond != gdconf.CaptainSkillUnlockCondCostItem {
		SendMsg(config.SC_CaptainSkillUnlockRsp, &pb.SC_CaptainSkillUnlockRsp{RetCode: config.SERVER_ERROR}, buf, user)
		return config.OK
	}
	ok = CostItems(map[int32]int32{unlockCond.Item.ItemId: unlockCond.Item.ItemCount}, user)
	if !ok {
		SendMsg(config.SC_CaptainSkillUnlockRsp, &pb.SC_CaptainSkillUnlockRsp{RetCode: config.ITEM_NOT_ENOUGH}, buf, user)
		return config.OK
	}
	role := user.GetRoleById(req.RoleId)
	if role == nil {
		SendMsg(config.SC_CaptainSkillUnlockRsp, &pb.SC_CaptainSkillUnlockRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	role.AddCaptainSkill(req.CaptainSkillGroup)
	role.SetSync()
	SendMsg(config.SC_CaptainSkillDataNtf, user.PacketUserRoleCaptainSkillData(), buf, user)

	SendMsg(config.SC_CaptainSkillUnlockRsp, &pb.SC_CaptainSkillUnlockRsp{RetCode: config.OK, RoleId: req.RoleId, CaptainSkillGroup: req.CaptainSkillGroup}, buf, user)
	return config.OK
}

func CaptainSkillUpgradeReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_CaptainSkillUpgradeReq, new(pb.CS_CaptainSkillUpgradeReq), buf, user).(*pb.CS_CaptainSkillUpgradeReq)
	if !ok {
		return config.PROTO_ERROR
	}

	role := user.GetRoleById(req.RoleId)
	if role == nil {
		SendMsg(config.SC_CaptainSkillUpgradeRsp, &pb.SC_CaptainSkillUpgradeRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	captainSkill := role.GetCaptainSkill(req.CaptainSkillGroup)
	if captainSkill == nil {
		SendMsg(config.SC_CaptainSkillUpgradeRsp, &pb.SC_CaptainSkillUpgradeRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	captainSkillLevelConfig := gdconf.GetCaptainSkillLevelConfigByGroupAndLevel(captainSkill.CaptainSkillGroup, int32(captainSkill.Level))
	if captainSkillLevelConfig == nil {
		SendMsg(config.SC_CaptainSkillUpgradeRsp, &pb.SC_CaptainSkillUpgradeRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	if captainSkillLevelConfig.CostItemList == nil {
		SendMsg(config.SC_CaptainSkillUpgradeRsp, &pb.SC_CaptainSkillUpgradeRsp{RetCode: config.SERVER_ERROR}, buf, user)
		return config.OK
	}
	itemMap := make(map[int32]int32)
	for _, item := range captainSkillLevelConfig.CostItemList {
		itemMap[item.ItemId] += item.ItemCount
	}
	ok = CostItems(itemMap, user)
	if !ok {
		SendMsg(config.SC_CaptainSkillUpgradeRsp, &pb.SC_CaptainSkillUpgradeRsp{RetCode: config.ITEM_NOT_ENOUGH}, buf, user)
		return config.OK
	}
	captainSkill.Level++
	role.SetSync()
	SendMsg(config.SC_CaptainSkillDataNtf, user.PacketUserRoleCaptainSkillData(), buf, user)

	SendMsg(config.SC_CaptainSkillUpgradeRsp, &pb.SC_CaptainSkillUpgradeRsp{RetCode: config.OK, RoleId: req.RoleId, CaptainSkillGroup: req.CaptainSkillGroup}, buf, user)
	return config.OK
}

func CaptainSkillChangeReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_CaptainSkillChangeReq, new(pb.CS_CaptainSkillChangeReq), buf, user).(*pb.CS_CaptainSkillChangeReq)
	if !ok {
		return config.PROTO_ERROR
	}

	switch req.Type {
	case pb.CaptainSkillChangeType_CaptainSkillChangeTypeRole:
		user.UserActivity.CaptainRoleId = req.RoleId
	case pb.CaptainSkillChangeType_CaptainSkillChangeTypeSkill:
		user.UserActivity.CaptainSkillRoleId = req.RoleId
		user.UserActivity.CaptainSkillGroup = req.CaptainSkillGroup
	default:
	}

	SendMsg(config.SC_CaptainSkillDataNtf, user.PacketUserRoleCaptainSkillData(), buf, user)

	SendMsg(config.SC_CaptainSkillChangeRsp, &pb.SC_CaptainSkillChangeRsp{RetCode: config.OK, RoleId: req.RoleId, CaptainSkillGroup: req.CaptainSkillGroup}, buf, user)
	return config.OK
}
